package cn.ztuo.bitrade.util;

import cn.ztuo.bitrade.constant.SysConstant;
import cn.ztuo.bitrade.entity.ContractCoin;
import cn.ztuo.bitrade.entity.ContractOrderPositionType;
import cn.ztuo.bitrade.entity.ContractPosition;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 获取指数工具类
 */

@Slf4j
@Component
public class DataUtilbak {
    static class SymbolMap {
        private String symbol;
        private BigDecimal price;
        public void setSymbol(String symbol) {
            this.symbol = symbol;
        }
        public String getSymbol() {
            return this.symbol;
        }
        public void setPrice(BigDecimal price) {
            this.price = price;
        }
        public BigDecimal getPrice() {
            return this.price;
        }
    }

    @Autowired
    private RestTemplate restTemplateDouble;
    @Autowired
    private RedisUtil redisUtilDouble;
    @Value("${index-source-file-path}")
    private String filePathDouble;

    private static RestTemplate restTemplate;
    private static RedisUtil redisUtil;
    private static String filePath;

    @PostConstruct
    public void init() {
        restTemplate = restTemplateDouble;
        redisUtil =  redisUtilDouble;
        filePath = filePathDouble;

    }


    //根据symbol获取当前指数价格
    public static BigDecimal getIndexPrice(String symbol){
        List<SymbolMap> symbolMaps = new ArrayList<>();
        List<SymbolMap> binance= DataUtilbak.getBinancePrice(restTemplate);
        binance=binance.stream().filter(a->a.getSymbol().equalsIgnoreCase(symbol)).collect(Collectors.toList());
        symbolMaps.addAll(binance);

        List<SymbolMap> huobi= DataUtilbak.getHuobiPrice(restTemplate);
        huobi=huobi.stream().filter(a->a.getSymbol().equalsIgnoreCase(symbol)).collect(Collectors.toList());
        symbolMaps.addAll(huobi);

        List<SymbolMap> okex= DataUtilbak.getOKEXPrice(restTemplate);
        okex=okex.stream().filter(a->a.getSymbol().equalsIgnoreCase(symbol)).collect(Collectors.toList());
        symbolMaps.addAll(okex);

        List<SymbolMap> poloniex= DataUtilbak.getPoloniexPrice(restTemplate);
        poloniex=poloniex.stream().filter(a->a.getSymbol().equalsIgnoreCase(symbol)).collect(Collectors.toList());
        symbolMaps.addAll(poloniex);

        List<SymbolMap> bitfinex= DataUtilbak.getBitfinexPrice(restTemplate);
        bitfinex=bitfinex.stream().filter(a->a.getSymbol().equalsIgnoreCase(symbol)).collect(Collectors.toList());
        symbolMaps.addAll(bitfinex);

//        List<SymbolMap> bittrex=DataUtil.getBittrexPrice(null);
//        bittrex=bittrex.stream().filter(a->a.getSymbol().equalsIgnoreCase(symbol)).collect(Collectors.toList());
//        symbolMaps.addAll(bittrex);


        if(symbolMaps.size()<=0){
            return null;
        }
        BigDecimal reduce = symbolMaps.stream().map(a -> a.getPrice()).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal indexPrice=reduce.divide(new BigDecimal(symbolMaps.size()), BigDecimal.ROUND_HALF_UP);
        return indexPrice;
    }

    //获取所有交易对 指数价格
    public static List<SymbolMap> getIndexPrice(){
        List<SymbolMap> symbolMaps = new ArrayList<>();
        List<String> symbols = Arrays.asList(new String[]{"BTCUSDT", "ETHUSDT", "EOSUSDT", "BSVUSDT", "LTCUSDT","HTUSDT","OKBUSDT","BNBUSDT"});
        symbols.stream().forEach(a->{
            SymbolMap symbolMap=new SymbolMap();
            symbolMap.setSymbol(a);
            symbolMap.setPrice(getIndexPrice(a));
            symbolMaps.add(symbolMap);
        });
        return symbolMaps;
    }


    /**
     * 获得Binance 交易所BTCUSDT的行情
     *
     * @param restTemplate
     * @return
     */
    private static List<SymbolMap> getBinancePrice(RestTemplate restTemplate) {
        if (restTemplate==null) {
            restTemplate = new RestTemplate();
        }
        List<SymbolMap> symbolMaps = new ArrayList<SymbolMap>();
//        String url = "https://api.binance.com/api/v3/ticker/price";
        try{
//            String forObject = restTemplate.getForObject(url, String.class, "");
            String forObject = readJsonFile(filePath+"binance.txt");
            if(!forObject.startsWith("[")||!forObject.endsWith("]")){
                return symbolMaps;
            }
            List<JSONObject> objs = JSONArray.parseArray(forObject, JSONObject.class);
            List<String> symbols = Arrays.asList(new String[]{"BTCUSDT", "ETHUSDT", "EOSUSDT","LTCUSDT", "BSVUSDT","BNBUSDT"});
            objs.stream().filter(a -> symbols.contains(a.getString("symbol"))).forEach(a -> {
                SymbolMap symbolMap = new SymbolMap();
                symbolMap.setSymbol(a.getString("symbol").toUpperCase());
                symbolMap.setPrice(a.getBigDecimal("price").setScale(8,BigDecimal.ROUND_HALF_DOWN));
                symbolMaps.add(symbolMap);
            });
        }catch (Exception e){
            e.printStackTrace();
        }
        return symbolMaps;
    }

    /**
     * 获取 Huobi 交易所BTCUSDT的行情
     *
     * @param restTemplate
     * @return
     */
    private static List<SymbolMap> getHuobiPrice(RestTemplate restTemplate) {
        List<String> symbols = Arrays.asList(new String[]{"BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT","BSVUSDT", "HTUSDT"});
        List<SymbolMap> symbolMaps = new ArrayList<SymbolMap>();
//        String url = "https://api.huobi.pro/market/tickers";
//        String s = HttpClientUtil.get(url, null, null);
        String s = readJsonFile(filePath+"huobi.txt");
        if(!s.startsWith("{")||!s.endsWith("}]")){
            return symbolMaps;
        }
        JSONObject jsonObject = JSONObject.parseObject(s);
        if (jsonObject.containsKey("status")&&jsonObject.getString("status").equals("ok")&&jsonObject.containsKey("data")) {
            List<JSONObject> objs = JSON.parseArray(jsonObject.getString("data"), JSONObject.class);
            objs.stream().filter(a -> symbols.contains(a.getString("symbol").toUpperCase())).forEach(a -> {
                SymbolMap symbolMap = new SymbolMap();
                symbolMap.setSymbol(a.getString("symbol").toUpperCase());
                symbolMap.setPrice(a.getBigDecimal("close").setScale(8,BigDecimal.ROUND_HALF_DOWN));
                symbolMaps.add(symbolMap);
            });
        }
        return symbolMaps;
    }

    /**
     * 获取 OKEX 交易所BTCUSDT的行情
     *
     * @param restTemplate
     * @return
     */
    private static List<SymbolMap> getOKEXPrice(RestTemplate restTemplate) {
        List<String> symbols = Arrays.asList(new String[]{"BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT","BSVUSDT", "OKBUSDT"});
        List<SymbolMap> symbolMaps = new ArrayList<SymbolMap>();
//        String url = "https://aws.okex.com/api/spot/v3/instruments/ticker";
//        String forObject = restTemplate.getForObject(url, String.class, "");
        String forObject = readJsonFile(filePath+"OKEX.txt");
        if(!forObject.startsWith("[{")||!forObject.endsWith("}]")){
            return symbolMaps;
        }
        List<JSONObject> objs = JSONArray.parseArray(forObject,JSONObject.class);
        objs.stream().filter(a -> symbols.contains(a.getString("instrument_id").replaceAll("-","").toUpperCase())).forEach(a -> {
            SymbolMap symbolMap = new SymbolMap();
            symbolMap.setSymbol(a.getString("instrument_id").replaceAll("-","").toUpperCase());
            symbolMap.setPrice(a.getBigDecimal("last").setScale(8,BigDecimal.ROUND_HALF_DOWN));
            symbolMaps.add(symbolMap);
        });
        return symbolMaps;
    }

    /**
     * 获取 Poloniex网 交易所的BTCUSDT 的行情
     *
     * @param restTemplate
     * @return
     */
    public static  List<SymbolMap> getPoloniexPrice(RestTemplate restTemplate) {
        List<SymbolMap> symbolMaps = new ArrayList<>();
        List<String> symbols = Arrays.asList(new String[]{"BTCUSDT", "ETHUSDT", "BSVUSDT"});
        String url = "https://poloniex.com/public?command=returnTicker";
//        String forObject = restTemplate.getForObject(url, String.class, "");
        String forObject = readJsonFile(filePath+"Poloniex.txt");
        if(!forObject.startsWith("{")||!forObject.endsWith("}}")){
            return symbolMaps;
        }
        JSONObject jsonObject = JSONObject.parseObject(forObject);
        for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
            String symbol=(entry.getKey().split("_")[1]+entry.getKey().split("_")[0]).toUpperCase();
            if(symbols.contains(symbol)){
                SymbolMap symbolMap = new SymbolMap();
                symbolMap.setSymbol(symbol);
                JSONObject value=JSON.parseObject(entry.getValue().toString());
                symbolMap.setPrice(value.getBigDecimal("last").setScale(8,BigDecimal.ROUND_DOWN));
                symbolMaps.add(symbolMap);
            }
        }
        return symbolMaps;
    }



    /**
     * 获取 B网 交易所的BTCUSDT 的行情
     *
     * @param restTemplate
     * @return
     */
    private static List<SymbolMap> getBittrexPrice(RestTemplate restTemplate) {
        List<String> symbols = Arrays.asList(new String[]{"USD-BTC", "USD-ETH"});
        String url = "https://api.bittrex.com/api/v1.1/public/getticker?market=";
        List<SymbolMap> symbolMaps = new ArrayList<SymbolMap>();
        for (String symbol:symbols){
//            String forObject = restTemplate.getForObject(url+symbol, String.class, "");
            String forObject = readJsonFile(filePath+"Poloniex.txt");
            if(!forObject.startsWith("{")||!forObject.endsWith("}}")){
                return symbolMaps;
            }
            JSONObject json=JSON.parseObject(forObject);
            if(json.containsKey("success")&&json.getBoolean("success")){
                List<JSONObject> objs=JSONArray.parseArray(json.getString("result"),JSONObject.class);
                SymbolMap symbolMap= new SymbolMap();
                symbolMap.setSymbol(symbol);
                symbolMap.setPrice(objs.get(0).getBigDecimal("Bid").setScale(8,BigDecimal.ROUND_DOWN));
                symbolMaps.add(symbolMap);
            }
        }
        return symbolMaps;
    }
    /**
     * 获取 B网 交易所的BTCUSDT 的行情
     *
     * @param restTemplate
     * @return
     */
    public static List<SymbolMap> getBitfinexPrice(RestTemplate restTemplate) {
        List<SymbolMap> symbolMaps = new ArrayList<SymbolMap>();
        List<String> symbols = Arrays.asList(new String[]{"BTCUSDT", "ETHUSDT"});
        String url = "https://api-pub.bitfinex.com/v2/tickers?symbols=ALL";
//        String forObject = restTemplate.getForObject(url, String.class, "");
        String forObject = readJsonFile(filePath+"Bitfinex.txt");
        if(!forObject.startsWith("[[")||!forObject.endsWith("]]")){
            return symbolMaps;
        }
        forObject=forObject.substring(2,forObject.length()-3);
        String[] list=forObject.split("],\\[");
//
        List<String> list1=Arrays.asList(list);
        list1.stream().filter(a->symbols.contains(a.split(",")[0].substring(2,a.split(",")[0].length()-1).toUpperCase()+"T")).forEach(a->{
            SymbolMap symbolMap=new SymbolMap();
            symbolMap.setSymbol(a.split(",")[0].substring(2,a.split(",")[0].length()-1).toUpperCase()+"T");
            symbolMap.setPrice(new BigDecimal(a.split(",")[1]).setScale(8,BigDecimal.ROUND_DOWN));
            symbolMaps.add(symbolMap);
        });
        return symbolMaps;
    }

    public static String readJsonFile(String fileName) {
        String jsonStr = "";
        try {
            File jsonFile = new File(fileName);
            FileReader fileReader = new FileReader(jsonFile);
            Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            fileReader.close();
            reader.close();
            jsonStr = sb.toString();
            return jsonStr;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static  BigDecimal getBreakPrice(ContractPosition position){
        ContractCoin coin = ContractUtils.getBaseSymbol(position.getSymbol());
        Object markPrice = redisUtil.get(SysConstant.CONTRACT_MARKED_PRICE + coin.getSymbol());
        if (markPrice == null) {
            markPrice = ContractUtils.getMarketprice().get(position.getSymbol());
        }
        BigDecimal marketPrice = new BigDecimal(markPrice.toString());
        BigDecimal orderNum = new BigDecimal(position.getContractOccupyNum()).multiply(coin.getMinVolume());
        BigDecimal a = orderNum.multiply(new BigDecimal("1").subtract(new BigDecimal("0.00075")));

        BigDecimal breakPrice = (orderNum.multiply(position.getPositionAvgPrice()).subtract(position.getHoldingBond())).divide(orderNum.multiply((new BigDecimal("1").subtract(new BigDecimal("0.00075")).setScale(8))),8,BigDecimal.ROUND_DOWN);
        return breakPrice;
    }

    public static BigDecimal getForcePrice(ContractPosition position){
        ContractCoin coin = ContractUtils.getBaseSymbol(position.getSymbol());
        BigDecimal orderNum = new BigDecimal(position.getContractOccupyNum()).multiply(coin.getMinVolume());
        BigDecimal breakPrice =  getBreakPrice(position);
        BigDecimal forcePrice = null;
        if (position.getPositionType()== ContractOrderPositionType.RISE) {
            forcePrice = (orderNum.multiply(position.getPositionAvgPrice())
                    .subtract(position.getHoldingBond())
                    .add(orderNum.multiply(new BigDecimal(0.00075)).multiply(breakPrice)))
                    .divide(orderNum.multiply(new BigDecimal(1).subtract(position.getMaintain())),8,BigDecimal.ROUND_DOWN);
        }
        if(position.getPositionType()== ContractOrderPositionType.FALL){
            forcePrice =position.getHoldingBond()
                    .add(orderNum.multiply(position.getPositionAvgPrice()))
                    .subtract(orderNum.multiply(new BigDecimal(0.00075)).multiply(breakPrice))
                    .divide(orderNum.multiply(new BigDecimal(1).add(position.getMaintain())),8,BigDecimal.ROUND_DOWN);
        }

        return forcePrice;
    }

    public static boolean isJson(String content) {
        try {
            JSON.parseObject(content);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    public static boolean getJSONType(String str) {
        boolean result = false;
        if (StringUtils.isNotBlank(str)) {
            str = str.trim();
            if (str.startsWith("{") && str.endsWith("}")) {
                result = true;
            } else if (str.startsWith("[") && str.endsWith("]")) {
                result = true;
            }
        }
        return result;
    }

}
